package com.pikts.acc2blender;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.Socket;
import com.pikts.acc2blender.data.DataStruct;
import com.pikts.acc2blender.data.Fifo;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends Activity {
	private static final String TAG = "Acc2BlenderLog";

	/**
	 * private Context context;
	 */
	private TextView accDataLabel;

	/**
	 * private Context context;
	 */
	private TextView rotDataLabel;

	/**
	 * private Context context;
	 */
	private TextView statusLabel;

	private Button connectButton;

	private ProgressBar progressBar;

	private com.pikts.acc2blender.data.Fifo fifoAcc = null;

	private com.pikts.acc2blender.data.Fifo fifoRot = null;

	/**
	 * private Text2Speech text2Speech; private TheThread theThread;
	 */
	private SensorListener sensorListener;

	private String serverIpAddress = "10.42.43.1";

	// private String serverIpAddress = "localhost";

	private boolean connected = false;

	private boolean exit = false;
	
	private boolean sensor_state = false; // false = off

	private int SERVER_PORT = 44444;

	private static int TIMEOUT = 5000;

	private static String HELLO_ANDROID = "hello_android";

	private static String HELLO_SERVER = "hello_server";

	//private static String SEND_NOW = "send_now";

	private static String STOP_NOW = "stop_now";

	private static String SEND_MORE = "send_more";
	
	private static String IDLE = "idle";

	Thread cThread = null;

	@Override
	protected void onStart() {
		super.onStart();
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		statusLabel = (TextView) findViewById(R.id.statusTextView);
		connectButton = (Button) findViewById(R.id.connectButton);
		connectButton.setOnClickListener(connectListener);
		progressBar = (ProgressBar) findViewById(R.id.progressBar);

		connect();

	}

	@Override
	protected void onPause() {
		// unregister listener
		// sensorManager.unregisterListener(sensorEventListener);
		super.onPause();
	}

	@Override
	protected void onResume() {
		super.onResume();

	}

	@Override
	protected void onStop() {
		super.onStop();
	}

	@Override
	protected void onDestroy() {
		stopThread();
		stopSensor();
		super.onDestroy();
	}

	public void updateAccRate(int rate) {

	}

	public void updateRotRate(int rate) {

	}

	private void startSensor() {
		fifoAcc = new Fifo();
		fifoRot = new Fifo();
		sensorListener = new SensorListener(fifoAcc, fifoRot, this);
		sensorListener.resume();
	}

	private void stopSensor() {
		if (sensorListener != null) {
			sensorListener.destroy();
			sensorListener = null;
		}
	}

	private void stopThread() {
		exit = true;

	}

	private void connect() {
		if (!connected) {
			if (!serverIpAddress.equals("")) {
				cThread = new Thread(new SocketThread());
				cThread.start();
			}
		}
	}

	private void updateProgressBar() {
		if (connected) {
			statusLabel.setText(R.string.statusConnected);
		} else
			statusLabel.setText(R.string.statusInitializing);
	}

	OnClickListener connectListener = new OnClickListener() {
		public void onClick(View v) {
			connect();
		}
	};

	public class SocketThread implements Runnable {
		private Socket socket;

		InetAddress serverAddr;

		BufferedReader in;

		PrintWriter out;

		/**
		 * welcomecounter
		 */
		private int wcnt = 1;

		private int length = 0;

		/**
		 * ilgio indeksas
		 */
		private int leni = 1;

		/**
		 * ilgis is net
		 */
		private String len = "";

		private int i = 0;

		private int state = 0;

		/**
		 * String line; int smb;
		 */
		int ismb;

		char smb;

		String cmd = "";

		private void loop() {
			while (connected) {
				if (parseCmd(readPacket())) {

					Log.d(TAG, i + " loop done");
					i++;
				}
				else {
					Log.d(TAG, "got unknown comand");
				}
			}
			Log.d(TAG, "escaping loop()");
		}

		private boolean parseCmd(String cmd) {
			Log.d(TAG, "parsing cmd: " + cmd);
			if (cmd==null) {
				return false;
			}
			if (cmd.equals(STOP_NOW)) {
				stopNow();
			}
			else if (cmd.equals(SEND_MORE)) {
				sendMore();
			}
			else if (cmd.equals(IDLE)) {
				// lets do nothing?
				idle();
			}
			else {
				Log.d(TAG, "message " + cmd + " was not understood");
				return false;
			}
			return true;
		}

		private void error(String cmd) {
			Log.d(TAG, "comand " + cmd + " was not understood");

		}

		//private void sendNow() {
		//	Log.d(TAG, "sendNow()");
		//	startSensor();
			//sendMore();
		//}
		
		private void idle() {
			Log.d(TAG, "idle()");
			out.print("idling"); //wrong
			out.flush();
			
		}
		private void stopNow() {
			stopSensor();
			sensor_state=false;
			connected=false;

		}

		private void sendMore() {
			if (!sensor_state) {
				startSensor();
				Log.d(TAG, "started (i hope) sensor");
				sensor_state=true;
			}
			Log.d(TAG, "sendMore()");
			for (int i = 0; i < 50; i++) {
				try {
					if (!fifoAcc.isLastEmpty()) {

						DataStruct temp = fifoAcc.pop();
						// out.println(Double.toString(fifoAcc.pop().timeStampAcc));
						// float test = temp.x;
						out.println(temp.x);
						out.println(temp.y);
						out.println(temp.z);
						out.println(temp.timeStampAcc);

						// out.println(Float.toString(temp.x));
						// out.println(Float.toString(temp.y));
						// out.println(Float.toString(temp.z));
					} else {
						Thread.sleep(100); // change me to 10
						i--;
					}
				} catch (Exception e) {
					Log.e(TAG, "exception in sendMore(): ", e);
				}
			}
			Log.d(TAG, "sendMore() finished");
		}

		private String readPacket() {
			while (connected) {
				try {
					if (exit) {
						connected = false;
						socket.close();
					}
					ismb = in.read();
					// Log.d(TAG, Integer.toString(ismb));
					if (ismb == -1) {
						Log.d(TAG, "disconected?? socket close");
						connected = false;
						break;
					}
					smb = (char) ismb;
					// Log.d(TAG, "loop state and read char is ");
					// Log.d(TAG, Character.toString(smb));
					// Log.d(TAG, Integer.toString(state));
					switch (state) {
					case 0: // syncin
						if ('!' == (char) smb) {
							wcnt++;
						}
						if (wcnt > 2) {
							wcnt = 1;
							//Log.d(TAG, "entering state2");
							state = 1;
							cmd=""; //nuresetinam komanda
						}
						break;
					case 1: // data length
						// Log.d(TAG, "packet length ");
						len = len + smb;
						Log.d(TAG, "packet length " + len);
						leni++;
						if (leni > 1) {
							leni = 1;

							// Log.d(TAG, "entering state3 length is");
							// Log.d(TAG, len);
							length = Integer.decode(len);
							len=""; //maybe 
							state = 3;
						}
						break;
					case 2: // data ID nr
						break;
					case 3: // data
						cmd = cmd + smb;
						leni++;
						//Log.d(TAG, "I m in read cmd state  length is "
						//		+ Integer.toString(length));
						if (length < leni) {
							leni = 1;
							state = 5;
							// Log.d(TAG, "entering state5  command is");
							// Log.d(TAG, cmd);
						}
						break;
					case 4: // CRC
						break;
					case 5: // end;
						if ('?' == (char) smb) {
							wcnt++;
							if (wcnt > 2) {
								wcnt = 1;
								state=0;
								// Log.d(TAG, "entering state0");
								// parseCmd(cmd);
								// out.println("trololo");
								return cmd; // grazinama komanda.
							}
						} else {
							error(cmd);
							state=0;
						}
						break;
					}
				} catch (Exception e) {
					Log.e(TAG, "S: Error analyzing packet", e);
					connected = false;
				}

			}
			return null;
		}

		private boolean handshake() {
			try {
				Log.d(TAG, "C: trying to handshake...");
				
				out.print(HELLO_SERVER);
				out.flush();
				// String line = in.readLine(); //BLOGAI
				char[] line = new char[20];
				// char[] line ;
				int nr = in.read(line);
				// line[nr] = '\0';
				if (-1 != nr) {
					Log.d(TAG, String.valueOf(line, 0, nr));
					// if (String.valueOf(line, 0 , nr) == HELLO_ANDROID) {
					if (String.valueOf(line, 0, nr).equals(HELLO_ANDROID)) {
						out.print("success");
						out.flush();
						Log.d(TAG, "handshake succesful");
						connected = true;
						return true;
					} else
						return false;
				} else
					return false;
			} catch (Exception e) {
				Log.e(TAG, "Error in handshake", e);
				connected = false;
				return false;
			}
		}
		private void calcCRC() throws UnsupportedEncodingException {
	        int crc = 0xFFFF;          // initial value
	        int polynomial = 0x1021;   // 0001 0000 0010 0001  (0, 5, 12) 

	        byte[] testBytes = "123456789".getBytes("ASCII");

	        //byte[] bytes = args[0].getBytes();
	        byte[] bytes = testBytes;

	        for (byte b : bytes) {
	        	System.out.println("Byte= " + b);
	            for (int i = 0; i < 8; i++) {
	                boolean bit = ((b   >> (7-i) & 1) == 1);
	                boolean c15 = ((crc >> 15    & 1) == 1);
	                crc <<= 1;
	                if (c15 ^ bit) crc ^= polynomial;
	             }
	        }

	        crc &= 0xffff;
	        System.out.println("CRC16-CCITT = " + crc+ "  " + Integer.toHexString(crc));
	    }

		public void run() {
			try {
				calcCRC();
				serverAddr = InetAddress.getByName(serverIpAddress);
				Log.d(TAG, "C: Connecting...");
				
				socket = new Socket(serverAddr, SERVER_PORT);
				socket.setSoTimeout(TIMEOUT);

				updateProgressBar();
				in = new BufferedReader(new InputStreamReader(
						socket.getInputStream()));
				out = new PrintWriter(new BufferedWriter(
						new OutputStreamWriter(socket.getOutputStream())), true);

				if (!handshake()) {
					Log.d(TAG, "cant do handshake...");
					socket.close();
				} else {
					Log.d(TAG, "susihandshakino (sun)");
					loop(); // important line
				}
				socket.close();
				Log.d(TAG, "C: Closed socket, exiting thread");
			} catch (Exception e) {
				Log.e(TAG, "C: exception in run()", e);
				connected = false;
			}
		}
	}

}
